home *** CD-ROM | disk | FTP | other *** search
/ 9-Digit Zip Code Directory / 9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO / z4src.zip / DASTRIP.C < prev    next >
C/C++ Source or Header  |  1995-09-11  |  11KB  |  380 lines

  1. //----------------------------------------------------------------------------
  2. //                            MODULE DESCRIPTION
  3. //
  4. //  Module:    dastrip.c
  5. //   Title:    Data File Build Utility Library
  6. //  Notice:    John M. Weeder
  7. //                 Copyright (c) 1993. All rights reserved.
  8. //             This module contains proprietary information and should be 
  9. //                treated as confidential.
  10. //
  11. //----------------------------------------------------------------------------
  12. //                           MAINTENANCE HISTORY
  13. //
  14. // $Workfile$
  15. // $Revision$
  16. //   $Author$
  17. //     $Date$
  18. //      $Log$    
  19. //
  20. //----------------------------------------------------------------------------
  21. //                             MODULE NARRATIVE
  22. //
  23. //
  24. //    This module contains code to strip a fixed length record file and create a
  25. //    delimited data file.
  26. //
  27. //    The code in this module should be written entirely in C. 
  28. //    Do not use any C++ constructs.
  29. //
  30. //    This module is portable to:
  31. //        DOS 3.X+
  32. //        MS Windows 3.X+
  33. //        OS/2 2.X+
  34. //        OS/2 2.0 PM
  35. //        SCO UNIX.
  36. //
  37. //    The following compilers are supported:
  38. //        MSC 6.0A
  39. //        MSC/C++ 7.0
  40. //        Borland C++ 3.1 for DOS
  41. //        Borland C++ 1.0 for OS/2 2.X
  42. //        SCO UNIX cc
  43. //
  44. //----------------------------------------------------------------------------
  45. #include <da.h>
  46.  
  47.  
  48. //----------------------------------------------------------------------------
  49. //    Global data
  50. //----------------------------------------------------------------------------
  51. typedef struct G                                // Global data
  52. {
  53.    PDATACFG pcfg;                                // Configuration data
  54.    PCHAR pchInput;                            // Input record buffer
  55.    PCHAR pchDelimit;                            // Delimited record buffer
  56.    PCHAR pchInputBuf;                        // Input record buffer
  57.    PCHAR pchDelimitBuf;                        // Delimited record buffer
  58.    PCHAR pchWork;                                // Work buffer
  59.    PDLMNDX pdlmndx;                            // Delimited record buffer
  60.    PDLMNDX pdlmndxBuf;                        // Delimited index buffer
  61.    SIZET cRecords;                            // Number of records in each pass
  62.     SIZET cWork;                                // Size of work area
  63.     HF hfInput;                                    // Input file
  64.     HF hfDelimit;                                // Delimited file
  65.     HF hfDelimitNdx;                            // Delimited file index
  66.     PFNSTRIPPROC pfn;                            // Strip function
  67. } G;
  68. static G g;
  69.  
  70. #define FL_OF                 (FL_OPEN|FL_READONLY\
  71.                                 |FL_DENYREADWRITE|FL_BINARY)
  72.  
  73. #define FL_CF                 (FL_TRUNCATE|FL_CREATE|FL_READWRITE\
  74.                                 |FL_DENYREADWRITE|FL_BINARY)
  75.  
  76.  
  77. //----------------------------------------------------------------------------
  78. //    Prototypes
  79. //----------------------------------------------------------------------------
  80. static SIZET FN_L DataStripDelimit(void);
  81. static BOOL FN_L DataStripFile(void);
  82. static BOOL FN_L DataStripProcess(void);
  83.  
  84.  
  85. //----------------------------------------------------------------------------
  86. //   Description:    Strip a data file
  87. //    Parameters:    pcfg        Configuration file data.
  88. //       Returns:    TRUE if successful.
  89. //----------------------------------------------------------------------------
  90. BOOL FN_E DataStrip(PDATACFG pcfg, PFNSTRIPPROC _pfn)
  91. {
  92.     BOOL fResult;
  93.     TIMET timetElapsed = time(NULL);
  94.  
  95.     Assert(pcfg);
  96.     memset(&g, 0, sizeof(g));                // Initialize file handles
  97.     g.pcfg = pcfg;
  98.     g.hfInput = -1;                            
  99.     g.hfDelimit = -1;
  100.     g.hfDelimitNdx = -1;
  101.     g.pfn = _pfn;
  102.  
  103.     fResult = DataStripFile();
  104.  
  105.     if (g.hfInput >= 0)                        // Close input files
  106.         FileClose(g.hfInput);
  107.     if (g.hfDelimit >= 0)
  108.         FileClose(g.hfDelimit);
  109.     if (g.hfDelimitNdx >= 0)
  110.         FileClose(g.hfDelimitNdx);
  111.     if (g.pchInputBuf)
  112.         MemFree(g.pchInputBuf);
  113.     if (g.pchWork)
  114.         MemFree(g.pchWork);
  115.     if (g.pchDelimitBuf)
  116.         MemFree(g.pchDelimitBuf);
  117.     if (g.pdlmndxBuf)
  118.         MemFree(g.pdlmndxBuf);
  119.     if (g.pcfg->fVerbose)
  120.         {
  121.         timetElapsed = time(NULL) - timetElapsed;
  122.         Output("Elapsed time %ld days, %ld hours, %ld minutes, %ld seconds.\n",
  123.             DAYS(timetElapsed), HOURS(timetElapsed),
  124.             MINUTES(timetElapsed), SECONDS(timetElapsed));
  125.         }
  126.     return fResult;
  127. }
  128.  
  129.  
  130. //----------------------------------------------------------------------------
  131. //   Description:    Strip spaces from fixed length file.
  132. //                          The last field is not null terminated!
  133. //    Parameters:    
  134. //       Returns:    Total length of buffer
  135. //----------------------------------------------------------------------------
  136. static SIZET FN_L DataStripDelimit(void)
  137. {
  138.     SIZET i, cFields = g.pcfg->cFields;
  139.     SIZET cTotal;
  140.     PBYTE pb;
  141.     PSZ apsz[MAX_FIELDS+1];                    // Pointers to fields
  142.     PRECID precid1, precid2;
  143.  
  144.     //
  145.     //    Copy the record into a work area and null terminate the
  146.     //    strings.
  147.     //
  148.     memset(g.pchWork, 0, g.cWork);        // Zero to start
  149.     pb = (PBYTE)g.pchWork;
  150.     precid1 = (PRECID)pb;
  151.     pb += sizeof(RECID);
  152.     for (i = 0; i < cFields; ++i)
  153.         {
  154.         apsz[i] = (PSZ)pb;
  155.         if (!BTEST(g.pcfg->afld[i].fs, FLD_USER))
  156.             {
  157.             memcpy(apsz[i], g.pchInput + g.pcfg->afld[i].cPos, g.pcfg->afld[i].cLen);
  158.             if (BTEST(g.pcfg->afld[i].fs, FLD_NUMERIC))
  159.                 {
  160.                 strcpy(apsz[i], strskipzero(apsz[i]));
  161.                 }
  162.             if (!BTEST(g.pcfg->afld[i].fs, FLD_FIXED))
  163.                 strtrim(apsz[i]);                // Trim spaces
  164.             }
  165.         pb += g.pcfg->afld[i].cLen + 1;
  166.         }
  167.     apsz[i] = NULL;
  168.     //
  169.     //    Call the user function for initial processing
  170.     //
  171.     if (g.pfn)                                    // Call user function for processing!
  172.         g.pfn(g.pcfg, precid1, apsz, (PBYTE)g.pchInput);
  173.     //
  174.     //    Copy the record into the output area!
  175.     //
  176.     pb = (PBYTE)g.pchDelimit;
  177.     precid2 = (PRECID)pb;                    // Set cross reference indicator!
  178.     *precid2 = *precid1;
  179.     cTotal = sizeof(RECID);
  180.     pb += sizeof(RECID);
  181.     for (i = 0; i < cFields; ++i)
  182.         {
  183.         SIZET cLen;
  184.         if (BTEST(g.pcfg->afld[i].fs, FLD_FIXED))
  185.             {
  186.             cLen = g.pcfg->afld[i].cLen;
  187.             memcpy(pb, apsz[i], cLen);
  188.             pb += cLen;
  189.             cTotal += cLen;
  190.             }
  191.         else
  192.             {
  193.             strtrim(apsz[i]);
  194.             cLen = strlen(apsz[i]);
  195.            Assert(cLen <= MAX_FIELD_LEN);
  196.            *pb++ = (BYTE)cLen;
  197.            cTotal++;
  198.            if (cLen)
  199.                {
  200.                memcpy(pb, apsz[i], cLen);
  201.                pb += cLen;
  202.                cTotal += cLen;
  203.                }
  204.             }
  205.         }
  206.     Assert(cTotal <= g.cWork);
  207.     return cTotal;
  208. }
  209.  
  210.  
  211. //----------------------------------------------------------------------------
  212. //   Description:    Open and process fixed length file.
  213. //    Parameters:    
  214. //       Returns:    TRUE if successful.
  215. //----------------------------------------------------------------------------
  216. static BOOL FN_L DataStripFile(void)
  217. {
  218.     SIZET cMax;
  219.     BOOL fResult;
  220.  
  221.     if (!FileOpen(&g.hfInput, g.pcfg->szInput, FL_OF, NULL))
  222.         return FALSE;
  223.  
  224.     if (g.pcfg->fVerbose)
  225.         Output("Opened input file '%s'\n", g.pcfg->szInput);
  226.  
  227.     if (!FileOpen(&g.hfDelimit, g.pcfg->szDelimit, FL_CF, NULL))
  228.         return FALSE;
  229.  
  230.     if (g.pcfg->fVerbose)
  231.         Output("Opened delimited file '%s'\n", g.pcfg->szDelimit);
  232.  
  233.     if (!FileOpen(&g.hfDelimitNdx, g.pcfg->szDelimitNdx, FL_CF, NULL))
  234.         return FALSE;
  235.  
  236.     if (g.pcfg->fVerbose)
  237.         Output("Opened delimited index file '%s'\n", g.pcfg->szDelimitNdx);
  238.  
  239. #if OS_UNIX
  240.     cMax = 1024 _K;
  241. #else
  242.     cMax = 0xFF00;
  243. #endif
  244.     g.cWork = g.pcfg->cUserLen + g.pcfg->cRecLen + g.pcfg->cFields + sizeof(RECID);
  245.     g.cRecords = cMax / g.cWork;
  246.     g.cRecords = MIN(g.cRecords, cMax / sizeof(DLMNDX));
  247.  
  248.     g.pchInputBuf   = MemAlloc(g.cRecords * g.pcfg->cRecLen);
  249.     g.pchWork = MemAlloc(g.cWork);
  250.     g.pchDelimitBuf = MemAlloc(g.cRecords * g.cWork);
  251.     g.pdlmndxBuf      = MemAlloc(g.cRecords * sizeof(DLMNDX));
  252.     if (g.pchInputBuf == NULL
  253.     || g.pchWork == NULL
  254.     || g.pchDelimitBuf == NULL
  255.     || g.pdlmndxBuf == NULL)
  256.         return ErrorNoMem();
  257.  
  258.     if (g.pfn)                                    
  259.         g.pfn(g.pcfg, NULL, NULL, NULL);
  260.     fResult = DataStripProcess();
  261.     if (g.pfn)                                    
  262.         g.pfn(g.pcfg, NULL, NULL, NULL);
  263.     return fResult;
  264. }
  265.  
  266.  
  267. //----------------------------------------------------------------------------
  268. //   Description:    Process records in fixed length file.
  269. //    Parameters:    pg        Pointer to global variables.
  270. //       Returns:    TRUE if successful.
  271. //----------------------------------------------------------------------------
  272. static BOOL FN_L DataStripProcess(void)
  273. {
  274.     FPOS fpos, fsize;
  275.     LONG lRec = 0, lRecs;
  276.     SIZET cSize;
  277.     SIZET i;
  278.     SIZET cDelimitBuf;
  279.     LONG lMax = 0;
  280.     LONG lSkip = 0;
  281.  
  282.  
  283.     if (!g.pcfg->fRecord)
  284.         return Error("Expected record definition to be specified.");
  285.  
  286.     fsize = FileGetSize(g.hfInput);
  287.     if (fsize < 0)
  288.         return FALSE;
  289.     
  290.     if (g.pcfg->fSkipFirst)
  291.         {
  292.         if (g.pcfg->lSkipFirst == 0)
  293.             lSkip = (LONG)g.pcfg->cRecLen;
  294.         else
  295.             lSkip = (LONG)g.pcfg->lSkipFirst;
  296.         }
  297.     fsize -= lSkip;
  298.     lRecs = fsize / (FPOS)g.pcfg->cRecLen;
  299.                                                     
  300.     if (fsize <= 0                                // Allow one extra byte for Ctrl-Z
  301.     || lRecs == 0
  302.     || ((fsize % (FPOS)g.pcfg->cRecLen) > 1))
  303.         Error("Input file has an invalid number of records.");
  304.  
  305.     fpos = (FPOS)lSkip;
  306.     if (!FileSetPos(g.hfInput, fpos, FL_BEGIN))
  307.         return FALSE;
  308.     fpos = 0;
  309.  
  310.     Output("\nProcessing %ld records\n", lRecs);
  311. #if OS_DOS ||OS_OS2
  312.     Output("Press <ESC> to abort processing...\n");
  313. #endif
  314.     Output("\n");
  315.  
  316.     for (lRec = 0; lRec < lRecs; )
  317.         {
  318.         if (g.pcfg->fVerbose)
  319.             {
  320. #if OS_UNIX
  321.             Output("%-10ld\n", lRec);
  322. #else
  323.             Output("\r%-10ld", lRec);
  324. #endif
  325.             while (KbdReady())
  326.                 if (KbdChar() == '\x1B')
  327.                     {
  328.                     Output("\r%-20s\rAborted.\n", "");
  329.                     return FALSE;
  330.                     }
  331.             }
  332.         if (g.cRecords > (ULONG)lRecs - (ULONG)lRec)    // Handle a partial buffer
  333.             g.cRecords = (SIZET)(lRecs - lRec);
  334.  
  335.         if (!FileRead(g.hfInput, g.pchInputBuf, g.cRecords * g.pcfg->cRecLen, -1))
  336.             return FALSE;
  337.  
  338.         cDelimitBuf =  0;
  339.         g.pchInput = g.pchInputBuf;
  340.         g.pchDelimit = g.pchDelimitBuf;
  341.         g.pdlmndx = g.pdlmndxBuf;
  342.         for (i = 0; i < g.cRecords; ++i)
  343.             {
  344.             cSize = DataStripDelimit();
  345.             g.pdlmndx->fpos = fpos;
  346.             g.pdlmndx->usLen = (USHORT)cSize;
  347.             lMax = MAX((LONG)lMax, (LONG)cSize);
  348.             fpos += (FPOS)cSize;
  349.             cDelimitBuf += cSize;
  350.             g.pchDelimit += cSize;
  351.             g.pchInput += g.pcfg->cRecLen;
  352.             g.pdlmndx++;
  353.             }
  354.         if (!FileWrite(g.hfDelimit, g.pchDelimitBuf, cDelimitBuf, -1))
  355.             return FALSE;
  356.         if (!FileWrite(g.hfDelimitNdx, g.pdlmndxBuf, g.cRecords * sizeof(DLMNDX), -1))
  357.             return FALSE;
  358.         lRec += g.cRecords;
  359.         }
  360.     if (g.pcfg->fVerbose)
  361.         {
  362. #if OS_UNIX == 0
  363.         Output("\r%-20s\r", "");
  364. #endif
  365.         Output("Processed %ld of %ld records.\n", lRec, lRecs);
  366.         Output("Average size was %ld bytes.\n", (LONG)(fpos / lRecs));
  367.         Output("Maximum size was %ld bytes.\n", lMax);
  368.         Output("Total size was %ld data, %ld index, %ld total.\n",
  369.             (LONG)fpos, (LONG)sizeof(DLMNDX) * lRecs,
  370.             (LONG)fpos + (LONG)sizeof(DLMNDX) * lRecs);
  371.         }
  372.     return TRUE;
  373. }
  374. //----------------------------------------------------------------------------
  375. //------------------------------- End of File --------------------------------
  376. //----------------------------------------------------------------------------
  377.  
  378.  
  379.  
  380.